package com.xhj.mybatis.reflection;

import com.xhj.mybatis.reflection.invoker.GetFieldInvoker;
import com.xhj.mybatis.reflection.invoker.Invoker;
import com.xhj.mybatis.reflection.invoker.MethodInvoker;
import com.xhj.mybatis.reflection.property.PropertyTokenizer;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;

/**
 * MetaClass
 *
 * @author XJks
 * @description 元类包装反射器。TODO:基于 Reflector 的类级导航器。其方法列表 hasGetter/hasSetter、findProperty、getGetterType 关注“类上是否存在这样一条属性路径”（不访问实例数据）。
 */
public class MetaClass {
    /**
     * 反射器工厂，用于创建和缓存 Reflector 实例
     */
    private final ReflectorFactory reflectorFactory;

    /**
     * 反射器，封装了对某个类的反射操作
     */
    private final Reflector reflector;

    /**
     * 构造方法，传入类型和反射器工厂，初始化成员变量
     *
     * @param type             要操作的类类型
     * @param reflectorFactory 反射器工厂
     */
    private MetaClass(Class<?> type, ReflectorFactory reflectorFactory) {
        this.reflectorFactory = reflectorFactory;
        this.reflector = reflectorFactory.findForClass(type);
    }

    /**
     * 静态工厂方法，创建 MetaClass 实例
     *
     * @param type             要操作的类类型
     * @param reflectorFactory 反射器工厂
     * @return MetaClass 实例
     */
    public static MetaClass forClass(Class<?> type, ReflectorFactory reflectorFactory) {
        return new MetaClass(type, reflectorFactory);
    }

    /**
     * 根据属性名获取该属性对应类型的 MetaClass
     *
     * @param name 属性名
     * @return 属性类型的 MetaClass
     */
    public MetaClass metaClassForProperty(String name) {
        // 获取属性的类型
        Class<?> propType = reflector.getGetterType(name);
        // 返回该类型的 MetaClass
        return MetaClass.forClass(propType, reflectorFactory);
    }

    /**
     * 查找属性名，返回规范化后的属性名（如驼峰命名）
     *
     * @param name 属性名
     * @return 规范化后的属性名，如果不存在则返回 null
     */
    public String findProperty(String name) {
        // 调用 buildProperty 方法，将 name 规范化（如处理多级属性、驼峰命名等），结果存入 StringBuilder
        StringBuilder prop = buildProperty(name, new StringBuilder());
        // 如果规范化后有内容，返回字符串，否则返回 null 表示未找到
        return prop.length() > 0 ? prop.toString() : null;
    }

    /**
     * 查找属性名，支持下划线转驼峰
     *
     * @param name                属性名
     * @param useCamelCaseMapping 是否启用驼峰映射
     * @return 规范化后的属性名，如果不存在则返回 null
     */
    public String findProperty(String name, boolean useCamelCaseMapping) {
        // 如果启用了驼峰命名映射（useCamelCaseMapping 为 true）
        if (useCamelCaseMapping) {
            // 将属性名中的下划线全部去掉（如 user_name 变为 username）
            name = name.replace("_", "");
        }
        // 调用 findProperty 方法查找规范化后的属性名
        return findProperty(name);
    }

    /**
     * 获取所有可读属性（有 getter 方法的属性）名称
     *
     * @return 属性名称数组
     */
    public String[] getGetterNames() {
        return reflector.getGetablePropertyNames();
    }

    /**
     * 获取所有可写属性（有 setter 方法的属性）名称
     *
     * @return 属性名称数组
     */
    public String[] getSetterNames() {
        return reflector.getSetablePropertyNames();
    }

    /**
     * 获取指定属性的 setter 方法参数类型，支持多级属性
     *
     * @param name 属性名
     * @return 属性的 setter 方法参数类型
     */
    public Class<?> getSetterType(String name) {
        // 解析属性名
        PropertyTokenizer prop = new PropertyTokenizer(name);
        // 如果有下一级属性
        if (prop.hasNext()) {
            // 获取当前属性的 MetaClass
            MetaClass metaProp = metaClassForProperty(prop.getName());
            // 递归获取下一级属性的类型
            return metaProp.getSetterType(prop.getChildren());
        } else {
            // 没有下一级，直接获取类型
            return reflector.getSetterType(prop.getName());
        }
    }

    /**
     * 获取指定属性的 getter 方法返回类型，支持多级属性
     *
     * @param name 属性名
     * @return 属性的 getter 方法返回类型
     */
    public Class<?> getGetterType(String name) {
        // 解析属性名
        PropertyTokenizer prop = new PropertyTokenizer(name);
        // 如果有下一级属性
        if (prop.hasNext()) {
            // 获取当前属性的 MetaClass
            MetaClass metaProp = metaClassForProperty(prop);
            // 递归获取下一级属性的类型
            return metaProp.getGetterType(prop.getChildren());
        }
        // 处理集合类型的属性，获取集合元素的类型
        return getGetterType(prop);
    }

    /**
     * 根据 PropertyTokenizer 获取属性类型对应的 MetaClass
     *
     * @param prop 属性解析器
     * @return 属性类型的 MetaClass
     */
    private MetaClass metaClassForProperty(PropertyTokenizer prop) {
        // 获取属性类型
        Class<?> propType = getGetterType(prop);
        // 返回该类型的 MetaClass
        return MetaClass.forClass(propType, reflectorFactory);
    }

    /**
     * 获取属性的类型，支持集合类型（如 List<User> 获取 User 类型）
     *
     * @param prop 属性解析器（用于解析多级属性和集合索引）
     * @return 属性类型的 Class 对象
     */
    private Class<?> getGetterType(PropertyTokenizer prop) {
        // 先通过属性名获取属性的类型（如 List<User> 会得到 List.class）
        Class<?> type = reflector.getGetterType(prop.getName());
        // 如果属性是集合类型，并且有索引（如 list[0]），则尝试获取集合的泛型类型
        if (prop.getIndex() != null && Collection.class.isAssignableFrom(type)) {
            // 获取 getter 方法的返回类型（可能带有泛型信息）
            Type returnType = getGenericGetterType(prop.getName());
            // 如果返回类型是参数化类型（如 List<User>）
            if (returnType instanceof ParameterizedType) {
                // 获取实际的泛型参数类型数组（如 [User.class]）
                Type[] actualTypeArguments = ((ParameterizedType) returnType).getActualTypeArguments();
                // 如果泛型参数存在且只有一个（如 List<User> 只有一个 User）
                if (actualTypeArguments != null && actualTypeArguments.length == 1) {
                    // 取出泛型参数类型
                    returnType = actualTypeArguments[0];
                    // 如果泛型参数是类类型（如 User.class），直接赋值给 type
                    if (returnType instanceof Class) {
                        type = (Class<?>) returnType;
                        // 如果泛型参数还是参数化类型（如 List<Map<String, Object>>），取其原始类型
                    } else if (returnType instanceof ParameterizedType) {
                        type = (Class<?>) ((ParameterizedType) returnType).getRawType();
                    }
                }
            }
        }
        // 返回最终确定的类型
        return type;
    }

    /**
     * 获取属性的泛型类型（如 List<User> 获取 User 类型）
     *
     * @param propertyName 属性名
     * @return 属性的泛型类型
     */
    private Type getGenericGetterType(String propertyName) {
        try {
            // 通过属性名获取对应的 getter 方法调用器（Invoker 是一个统一的调用接口，可能代表方法或字段）
            Invoker invoker = reflector.getGetInvoker(propertyName);
            // 如果这个调用器是方法类型（即通过 getter 方法获取属性）
            if (invoker instanceof MethodInvoker) {
                // 反射获取 MethodInvoker 类中的私有字段 "method"
                Field declaredMethod = MethodInvoker.class.getDeclaredField("method");
                // 设置为可访问，突破 private 限制
                declaredMethod.setAccessible(true);
                // 从 invoker 实例中取出实际的 Method 对象
                Method method = (Method) declaredMethod.get(invoker);
                // 解析并返回该方法的返回类型（包括泛型信息）
                return TypeParameterResolver.resolveReturnType(method, reflector.getType());
            } else if (invoker instanceof GetFieldInvoker) {
                // 如果这个调用器是字段类型（即直接通过字段获取属性）
                // 反射获取 GetFieldInvoker 类中的私有字段 "field"
                Field declaredField = GetFieldInvoker.class.getDeclaredField("field");
                // 设置为可访问，突破 private 限制
                declaredField.setAccessible(true);
                // 从 invoker 实例中取出实际的 Field 对象
                Field field = (Field) declaredField.get(invoker);
                // 解析并返回该字段的类型（包括泛型信息）
                return TypeParameterResolver.resolveFieldType(field, reflector.getType());
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            // 如果反射过程中出现异常（如字段不存在或无法访问），这里选择忽略异常
        }
        // 如果没有获取到泛型类型，则返回 null
        return null;
    }

    /**
     * 判断指定属性名是否有对应的 setter 方法，支持多级属性
     *
     * @param name 属性名
     * @return 是否有 setter 方法
     */
    public boolean hasSetter(String name) {
        // 解析属性名
        PropertyTokenizer prop = new PropertyTokenizer(name);
        // 如果有下一级属性
        if (prop.hasNext()) {
            // 当前级别有 setter
            if (reflector.hasSetter(prop.getName())) {
                // 获取当前属性的 MetaClass
                MetaClass metaProp = metaClassForProperty(prop.getName());
                // 递归判断下一级
                return metaProp.hasSetter(prop.getChildren());
            } else {
                // 当前级别没有 setter
                return false;
            }
        } else {
            // 没有下一级，直接判断
            return reflector.hasSetter(prop.getName());
        }
    }

    /**
     * 判断指定属性名是否有对应的 getter 方法，支持多级属性
     *
     * @param name 属性名
     * @return 是否有 getter 方法
     */
    public boolean hasGetter(String name) {
        // 解析属性名
        PropertyTokenizer prop = new PropertyTokenizer(name);
        // 如果有下一级属性
        if (prop.hasNext()) {
            // 当前级别有 getter
            if (reflector.hasGetter(prop.getName())) {
                // 获取当前属性的 MetaClass
                MetaClass metaProp = metaClassForProperty(prop);
                // 递归判断下一级
                return metaProp.hasGetter(prop.getChildren());
            } else {
                // 当前级别没有 getter
                return false;
            }
        } else {
            // 没有下一级，直接判断
            return reflector.hasGetter(prop.getName());
        }
    }

    /**
     * 获取属性的 getter 方法调用器
     *
     * @param name 属性名
     * @return 属性的 getter 方法调用器
     */
    public Invoker getGetInvoker(String name) {
        return reflector.getGetInvoker(name);
    }

    /**
     * 获取属性的 setter 方法调用器
     *
     * @param name 属性名
     * @return 属性的 setter 方法调用器
     */
    public Invoker getSetInvoker(String name) {
        return reflector.getSetInvoker(name);
    }

    /**
     * 递归构建规范化的属性名（如 user.address.street），支持多级属性
     *
     * @param name    属性名（可能是多级，如 user.address.street）
     * @param builder 用于拼接属性名的 StringBuilder
     * @return 拼接好的规范化属性名
     */
    private StringBuilder buildProperty(String name, StringBuilder builder) {
        // 用 PropertyTokenizer 解析属性名，支持多级属性（如 user.address.street 会被拆分）
        PropertyTokenizer prop = new PropertyTokenizer(name);
        // 判断当前属性后面是否还有子属性（如 user.address.street，user 后面还有 address.street）
        if (prop.hasNext()) {
            // 查找当前级别属性的真实名称（如处理驼峰、下划线等映射）
            String propertyName = reflector.findPropertyName(prop.getName());
            // 如果找到了对应的属性名
            if (propertyName != null) {
                // 追加当前属性名到 builder
                builder.append(propertyName);
                // 追加点号，表示多级属性
                builder.append(".");
                // 获取当前属性对应类型的 MetaClass，用于递归处理下一级属性
                MetaClass metaProp = metaClassForProperty(propertyName);
                // 递归处理下一级属性（如 address.street）
                metaProp.buildProperty(prop.getChildren(), builder);
            }
        } else {
            // 如果没有下一级属性，处理最后一级
            String propertyName = reflector.findPropertyName(name);
            // 如果找到了对应的属性名
            if (propertyName != null) {
                // 追加最后一级属性名到 builder
                builder.append(propertyName);
            }
        }
        // 返回拼接好的属性名
        return builder;
    }

    /**
     * 判断类是否有无参构造方法
     *
     * @return 是否有无参构造方法
     */
    public boolean hasDefaultConstructor() {
        return reflector.hasDefaultConstructor();
    }

}
